'use strict';

/**
 * 识别记录逻辑控制器
 */
const Code = require('../common/error_code');
const Cons = require('../common/constants');
const userRecordModel = require('../models/record_user.model');
const strangerRecordModel = require('../models/record_stranger.model');
const studentRecordModel = require('../models/record_student.model');

const IpcCtrl = require('../controllers/ipc');
const Util = require('../utils/hobot_util');
const Config = require('../controllers/config');
const fs = require('fs');
const archiver = require('archiver');
const send = require('koa-send');
const request = require('request-promise');
const globalConfig = require('../../config/global_config');
const resConfig = globalConfig.res;
const userModel = require('../models/user.model');
const logger = require('../utils/logger');
const publicIp = require('public-ip');

/**
 * 压缩要下载的特征图
 * @param ctx
 * @returns {Promise.<void>} 如果压缩正确，则返回下载路径
 */
async function getDownloadUrl(ctx) {
    const params = ctx.request.query;

    const recId = params.rec_id;
    const zipDir = resConfig.capture_dir;
    const zipFile = recId + '.zip';
    if (!params.rec_id || !params.type || [Cons.RECORD_TYPE_REGISTER, Cons.RECORD_TYPE_STRANGER].indexOf(params.type) < 0) {
        return ctx.error(Code.RET_RECORD_DOWNLOAD_FEATURE_ERR_PARAM);
    }
    // 缓存文件夹，如果不存在则创建
    if (!fs.existsSync(zipDir)) {
        fs.mkdirSync(zipDir);
    }
    let rst;
    if (params.type == Cons.RECORD_TYPE_REGISTER) {
        rst = await userRecordModel.findById(recId, { u_id: 1, b_qp: 1, r_at: 1 });
    } else {
        rst = await strangerRecordModel.findById(recId, { u_id: 1, b_qp: 1, r_at: 1 });
    }
    let downloadFileName;
    const time = Util.fmtDate(rst.r_at);
    if (params.type == Cons.RECORD_TYPE_REGISTER) {
        downloadFileName = 'user_' + time + '.zip';
    } else {
        downloadFileName = 'stranger_' + time + '.zip';
    }
    // 如果文件不存在，则先进行压缩
    if (!fs.existsSync(zipDir + '/' + zipFile)) {
        if (rst && rst.b_qp && rst.b_qp instanceof Array && rst.b_qp.length > 0) {
            const archive = archiver.create('zip', {});
            archive.pipe(fs.createWriteStream(zipDir + '/' + zipFile));
            for (let i = 0; i < rst.b_qp.length; i++) {
                const item = Util.getCaptureUrl(rst.b_qp[i]);
                const buffer = await request({ url: item, encoding: null });
                await archive.append(buffer, { 'name': 'img_' + i + '.jpeg' });
            }
            await archive.finalize();
        } else {
            ctx.error(Code.RET_RECORD_DOWNLOAD_FEATURE_ERR_NONECAPTURE);
            return;
        }
    }
    // 如果压缩没出错，下载文件
    ctx.success(Code.RET_RECORD_DOWNLOAD_FEATURE_OK, {
        path: zipFile,
        name: downloadFileName,
        dir: zipDir
    })
}

/**
 * 下载压缩包
 * @param ctx
 * @returns {Promise.<void>}
 */
async function downloadCapture(ctx) {
    const params = ctx.request.query;

    const path = params.path;
    const name = params.name;
    const dir = params.dir;

    await send(ctx, path, {
        root: dir,
        setHeaders: (res, path, stats) => {
            res.setHeader('Content-Disposition', 'filename=' + name)
        }
    })
}

/**
 * @deprecated 查询识别记录（因关联查询效率低，被废弃）
 */
async function query_bak(ctx) {
    // const params = ctx.request.query;
    // try {
    //     // 校验参数
    //     if (!params.page_num || !params.page_size) {
    //         return ctx.error(Code.RET_RECORD_QUERY_ERR_PARAM);
    //     }
    //     if (params.type && params.type !== Cons.RECORD_TYPE_REGISTER && params.type !== Cons.RECORD_TYPE_STRANGER) {
    //         return ctx.error(Code.RET_RECORD_QUERY_ERR_PARAM);
    //     }
    //     if (params.user_type && params.user_type != Cons.USER_TYPE_STAFF && params.user_type != Cons.USER_TYPE_TRAINEE
    //         && params.user_type != Cons.USER_TYPE_GUEST && params.user_type != Cons.USER_TYPE_VIP) {
    //         return ctx.error(Code.RET_RECORD_QUERY_ERR_PARAM);
    //     }
    //     if ((params.date_from && !params.date_to) || (params.date_to && !params.date_from)) {
    //         return ctx.error(Code.RET_RECORD_QUERY_ERR_PARAM);
    //     }
    //
    //     let records;
    //     let rst = [];
    //     // 注册用户
    //     if (!params.type || params.type == Cons.RECORD_TYPE_REGISTER) {
    //         const match1 = {$and: [{u_id: {$ne: null}}, {u_id: {$ne: ''}}]};
    //         if (params.date_from || params.date_to) {
    //             match1.r_at = {
    //                 $gte: new Date(Util.toISODate(params.date_from, 'YYYYMMDDHHmmss')),
    //                 $lte: new Date(Util.toISODate(params.date_to, 'YYYYMMDDHHmmss'))
    //             };
    //         }
    //         const lookup = {
    //             from: "user",
    //             localField: "u_id",
    //             foreignField: "_id",
    //             as: "user_docs"
    //         };
    //         const project1 = {_id: 1, u_id: 1, r_at: 1, d_id: 1, user: {$arrayElemAt: ["$user_docs", 0]}};
    //         const project2 = {_id: 1, u_id: 1, r_at: 1, d_id: 1, u_nm: "$user.u_nm", u_tp: "$user.u_tp"};
    //         const match2 = {};
    //         if (params.user_name) {
    //             match2.u_nm = {$regex: params.user_name};
    //         }
    //         if (params.user_type) {
    //             match2.u_tp = Number(params.user_type);
    //         }
    //
    //         const start = new Date().getTime();
    //         const pageParams = [{$match: match1}, {$lookup: lookup}, {$project: project1},
    //             {$project: project2}, {$match: match2}];
    //         // count管道暂时用不了，就先这么解决
    //         const countParams = [{$match: match1}, {$lookup: lookup}, {$project: project1},
    //             {$project: project2}, {$match: match2}, {$group: {_id: null, total: {$sum: 1}}}];
    //         records = await pageAggregate(params.page_num, params.page_size, recordModel,
    //             countParams, pageParams, {'r_at': -1});
    //
    //         const end = new Date().getTime();
    //         console.log('总耗时: ' + (end - start) + "ms");
    //
    //         if (records && records.results && records.results.length > 0) {
    //             const config = await Config.getUserType();
    //             for (let i = 0; i < records.results.length; i++) {
    //                 const item = records.results[i];
    //                 rst.push({
    //                     rec_id: item._id,
    //                     user_id: item.u_id,
    //                     user_type: Config.getConfigLabel(types, item.u_tp),
    //                     user_name: item.u_nm,
    //                     rec_time: item.r_at ? Util.fmtDate(item.r_at, 'YYYYMMDDHHmmss') : ''
    //                 });
    //             }
    //         }
    //
    //     } else {
    //         let cdt = {$or: [{u_id: null}, {u_id: ''}]};
    //         if (params.date_from || params.date_to) {
    //             cdt.r_at = {
    //                 $gte: new Date(Util.toISODate(params.date_from, 'YYYYMMDDHHmmss')),
    //                 $lte: new Date(Util.toISODate(params.date_to, 'YYYYMMDDHHmmss'))
    //             };
    //         }
    //
    //         const opt = {
    //             r_cp: 0
    //         };
    //         records = await Util.pageQuery(params.page_num, params.page_size, recordModel, cdt, opt, '', {'r_at': -1});
    //
    //         if (records && records.results && records.results.length > 0) {
    //             for (let i = 0; i < records.results.length; i++) {
    //                 const item = records.results[i];
    //                 rst.push({
    //                     rec_id: item._id,
    //                     rec_time: item.r_at ? Util.fmtDate(item.r_at, 'YYYYMMDDHHmmss') : ''
    //                 });
    //             }
    //         }
    //     }
    //
    //     ctx.success(Code.RET_RECORD_QUERY_OK, {
    //         page_num: params.page_num,
    //         page_size: params.page_size,
    //         total: records.total,
    //         result: rst
    //     });
    // } catch (err) {
    //     ctx.error(Code.RET_RECORD_QUERY_ERR_SERVER);
    // }
}

/**
 * 查询识别记录
 * 根据检索条件，最多检索Cons.RECORD_MAX条数据，展示端自行分页
 */
async function query(ctx) {
    const params = ctx.request.query;

    // 校验参数
    // 固定最多返回Cons.RECORD_MAX条
    if (params.type && params.type !== Cons.RECORD_TYPE_REGISTER && params.type !== Cons.RECORD_TYPE_STRANGER) {
        return ctx.error(Code.RET_RECORD_QUERY_ERR_PARAM);
    }
    if (params.user_type && params.user_type != Cons.USER_TYPE_STAFF && params.user_type != Cons.USER_TYPE_TRAINEE
        && params.user_type != Cons.USER_TYPE_GUEST && params.user_type != Cons.USER_TYPE_VIP
        && params.user_type != Cons.USER_TYPE_STRANGER) {
        return ctx.error(Code.RET_RECORD_QUERY_ERR_PARAM);
    }
    if ((params.date_from && !params.date_to) || (params.date_to && !params.date_from)) {
        return ctx.error(Code.RET_RECORD_QUERY_ERR_PARAM);
    }

    let records;
    let rst = [];
    // 注册用户
    if (!params.type || params.type == Cons.RECORD_TYPE_REGISTER) {
        let cdt = {
            u_tp: { "$gte": Cons.USER_TYPE_STAFF, "$lt": Cons.USER_TYPE_STRANGER }
        };
        if (params.user_name) {
            cdt.u_nm = { $regex: params.user_name };
        }
        if (params.user_type) {
            cdt.u_tp = Number(params.user_type);
        }
        if (params.date_from || params.date_to) {
            cdt.r_at = {
                $gte: new Date(Util.toISODate(params.date_from, 'YYYYMMDDHHmmss')),
                $lte: new Date(Util.toISODate(params.date_to, 'YYYYMMDDHHmmss'))
            };
        }
        records = await pageQuery(userRecordModel, cdt, { b_qp: 0 }, { r_at: -1 });

        if (records && records.results && records.results.length > 0) {
            const types = await Config.getUserType();
            const ipcList = await IpcCtrl.getIpcList();
            for (let i = 0; i < records.results.length; i++) {
                const item = records.results[i];
                rst.push({
                    rec_id: item._id,
                    ipc_id: item.d_id,
                    ipc_name: Config.getConfigLabel(ipcList, item.d_id),
                    user_id: item.u_id,
                    user_avatar: Util.getAvatarUrl(item.u_hp),
                    user_type: Config.getConfigLabel(types, item.u_tp),
                    user_name: item.u_nm,
                    rec_capture: Util.getCaptureUrl(item.r_cp),
                    rec_time: item.r_at ? Util.fmtDate(item.r_at, 'YYYYMMDDHHmmss') : '',
                    liveness: item.liveness             
                });
            }
        }

    } else {
        let cdt = {};
        if (!params.page_num || !params.page_size) {
            return ctx.error(Code.RET_ERR_PARAM);
        }
        if (params.date_from || params.date_to) {
            cdt.r_at = {
                $gte: new Date(Util.toISODate(params.date_from, 'YYYYMMDDHHmmss')),
                $lte: new Date(Util.toISODate(params.date_to, 'YYYYMMDDHHmmss'))
            };
        }
        if (params.group_name) {
            cdt.group_name = { $regex: params.group_name };
        }
        if (params.campus_name) {
            cdt.campus_name = { $regex: params.campus_name };
        }
        if (params.class_name) {
            cdt.class_name = { $regex: params.class_name };
        }
        records = await Util.pageQuery(params.page_num, params.page_size,strangerRecordModel, cdt, '','', { 'r_at': -1 });
        const public_ip = await publicIp.v4();
        if (records && records.results && records.results.length > 0) {
            const ipcList = await IpcCtrl.getIpcList();
            for (let i = 0; i < records.results.length; i++) {
                const item = records.results[i];
                rst.push({
                    rec_id: item._id,
                    ipc_id: item.d_id,
                    ipc_name: Config.getConfigLabel(ipcList, item.d_id),
                    rec_capture: item.d_uuid ? Util.getBase64ImgUrl(item.r_cp) : Util.getCaptureUrl(item.r_cp), //巨龙设备图片是base64
                    rec_time: item.r_at ? Util.fmtDate(item.r_at, 'YYYY-MM-DD HH:mm:ss') : '',
                    liveness: item.liveness,
                    // 巨龙设备uuid
                    d_uuid: item.d_uuid,
                    c_photo_name:item.c_photo_name,
                    c_photo_path: item.c_photo_name?Util.formatCaputureUrl(public_ip,item.c_photo_name):'',
                    // 所在教室信息
                    group_name:item.group_name,//集团名称
                    campus_name:item.campus_name,//校区名称
                    class_name:item.class_name,//班级名称
                    classroom_id:item.classroom_id,//教室id
                    classroom_name:item.classroom_name,//教室名称
                    classroom_num:item.classroom_num,//教室编号
                });
            }
        }
    }

    ctx.success(Code.RET_RECORD_QUERY_OK, {
        total: records.total,
        result: rst
    });
}

async function pageQuery(model, queryParams, opt, sortParams) {
    let ret = {};
    // 查询数量
    let count = await model.find(queryParams, opt).count();
    if (count > Cons.RECORD_MAX) {
        count = Cons.RECORD_MAX;
    }
    // 查询一页的记录
    const records = await model.find(queryParams, opt).limit(count).sort(sortParams);
    ret.total = count;
    ret.results = records;
    return ret;
}

/**
 * 删除用户信息
 */
async function del(ctx) {
    const params = ctx.request.body;

    // 校验参数
    if (!params.rec_id || !params.type) {
        return ctx.error(Code.RET_RECORD_DELETE_ERR_PARAM);
    }
    if (params.type && params.type !== Cons.RECORD_TYPE_REGISTER && params.type !== Cons.RECORD_TYPE_STRANGER) {
        return ctx.error(Code.RET_RECORD_QUERY_AVATAR_ERR_PARAM);
    }

    if (!params.type || params.type == Cons.RECORD_TYPE_REGISTER) {
        await userRecordModel.remove({ _id: params.rec_id });
    } else {
        await strangerRecordModel.remove({ _id: params.rec_id });
    }
    ctx.success(Code.RET_RECORD_DELETE_OK);
}

async function clean(ctx) {
    await userRecordModel.remove();
    await strangerRecordModel.remove();
    ctx.success(Code.RET_RECORD_CLEAN_OK);
}
// /**
//  * 分页处理
//  * @param pageNumber
//  * @param pageSize
//  * @param model
//  * @param countParams
//  * @param pageParams
//  * @param sortParams
//  * @returns {Promise.<{pageNumber: number}>}
//  */
// async function pageAggregate(pageNumber, pageSize, model, countParams, pageParams, sortParams) {
//     const size = Number(pageSize);
//     const start = (pageNumber - 1) * size;
//     let ret = {
//         pageNumber: Number(pageNumber)
//     };
//
//     // 查询数量 TODO
//     const start1 = new Date().getTime();
//     let total = 20000;
//     const rst = await model.aggregate(countParams);
//     if (rst && rst.length > 0) {
//         total = rst[0].total;
//     }
//     const end1 = new Date().getTime();
//     console.log('查询数量耗时: ' + (end1 - start1) + "ms");
//
//     // 查询一页的记录
//     const start2 = new Date().getTime();
//     const records = await model.aggregate(pageParams).sort(sortParams).skip(start).limit(size);
//     const end2 = new Date().getTime();
//     console.log('查询一页的记录耗时: ' + (end2 - start2) + "ms");
//     ret.pageCount = Math.ceil(total / size);
//     ret.total = total;
//     ret.results = records;
//     return ret;
// }

let process = {};

process.msg_callback = async function (channel, message) {
    // if (message.liveness == undefined || message.liveness == Cons.RECORD_LIVENESS_NOT_CHECK)
    //     return;
    const urlPath = message.face_info.r_cp;
    const picPath = urlPath.substr(resConfig.base_record_uri.length,
        urlPath.length - resConfig.base_record_uri.length);

    const id = picPath.split('_')[2];
    const udt = {
        _id: id
    };
    const params = {
        liveness: message.liveness
    };
    // TODO check which one to update.
    await userRecordModel.update(udt, params);
    await strangerRecordModel.update(udt, params);
}

async function recordToUser(ctx) {
    let params = ctx.request.body;
    if (!params.rec_id || !params.user_id) {
        return ctx.error(Code.RET_RECORD_TO_USER_ERR_PARAMS);
    }
    let record = await strangerRecordModel.findOne({
        _id: params.rec_id
    });
    let user = await userModel.findOne({
        _id: params.user_id
    });
    if (!record || !user) {
        return ctx.error(Code.RET_RECORD_TO_USER_ERR_NOT_EXISTS);
    }

    let model = {
        _id: params.rec_id,
        u_id: params.user_id,
        r_at: record.r_at,
        r_cp: record.r_cp,
        d_id: record.d_id,
        u_nm: user.u_nm,
        u_sx: user.u_sx,
        u_tp: user.u_tp,
        u_hp: user.u_hp,
        u_no: user.u_no,
        u_dm: user.u_dm,
        u_pn: user.u_pn,
        u_em: user.u_em,
        u_pt: user.u_pt,
        g_mk: user.g_mk,
        g_cp: user.g_cp,
        g_re: user.g_re,
        u_st: user.u_st,
        p_fr: user.p_fr,
        p_to: user.p_to,
        b_qp: record.b_qp,
        c_id: record.c_id,
        m_id: record.m_id,
        c_at: record.c_at,
        m_at: record.m_at,
        liveness: record.liveness
    };

    await userRecordModel.create(model);
    await strangerRecordModel.remove({
        _id: params.rec_id
    });

    ctx.success(Code.RET_RECORD_TO_USER_SUCCESS);
}

// 获取学生记录
async function getStudentRecord(ctx, next) {
    const params = ctx.request.body
    const queryParams = {
    }
    if(!params.page_size||!params.page_num){
        ctx.error(Code.REQUEST_ERROR('缺少参数'))
    }
    if (params.group_name) {
        cdt.group_name = { $regex: params.group_name };
    }
    if (params.campus_name) {
        cdt.campus_name = { $regex: params.campus_name };
    }
    if (params.class_name) {
        cdt.class_name = { $regex: params.class_name };
    }
    if (params.name){
        queryParams.s_name = {
            "$regex": new RegExp(params.name,'i')
        }
    }
    if(params.date_from || params.data_to){
        queryParams.c_time = {
            '$gte': params.date_from,
            '$lte': params.date_to
        }
    }
    if(params.type){
        const type = Number(params.type)
        if(type>0 && type<=4) {
            queryParams.p_type = type
        } 
    }
    try{
        const students = await Util.pageQuery(params.page_num, params.page_size, studentRecordModel,
         queryParams, '', '', {_id: -1});
        const results = [];
        const public_ip = await publicIp.v4();
        students.results.forEach(item=>{
            results.push({
                c_time:item.c_time,
                c_photo:Util.getBase64ImgUrl(item.c_photo),
                c_photo_name:item.c_photo_name,
                c_photo_path:item.c_photo_name?Util.formatCaputureUrl(public_ip,item.c_photo_name):'',
                d_id:item.d_id,
                d_name:item.d_name,
                s_similarity:item.s_similarity,
                s_id:item.s_id,
                s_name:item.s_name,
                s_sex:item.s_sex,
                s_num:item.s_num,
                s_school:item.s_school,
                s_class:item.s_class,
                group_name:item.group_name,
                campus_name:item.campus_name,
                class_name:item.class_name,
                classroom_name:item.classroom_name,
                classroom_num:item.classroom_num
            })
        })
        return ctx.success(
            Code.REQUEST_SUCCESS('请求成功'), 
            {
                page_num: params.page_num,
                page_size: params.page_size,
                total:students.total,
                result:results
            }
        )
    }catch(err){
        ctx.error(Code.REQUEST_ERROR('请求失败'))
    }
}

// 查看记录照片
async function getStudentCapturePhoto(ctx,next){
    const params = ctx.request.body
    if(!params._id){
        ctx.error(Code.REQUEST_ERROR('缺少参数'))
    }
    const record = await studentRecordModel.findById(params._id)
    if(!record){
        return ctx.error(Code.REQUEST_ERROR('记录不存在'))
    }
    return ctx.success(Code.REQUEST_SUCCESS('查询成功'),record.c_photo)
}

//下载抓拍前后几帧图片
exports.downloadCapture = downloadCapture;
exports.getDownloadUrl = getDownloadUrl;
// 查询识别记录
exports.query = query;
// 删除识别记录
exports.delete = del;

// 清空历史记录
exports.clean = clean;

// 记录后处理
exports.process = process;

exports.recordToUser = recordToUser;

// 学生记录
exports.getStudentRecord = getStudentRecord

exports.getStudentCapturePhoto = getStudentCapturePhoto